﻿using System.Linq;
using CID.Domain.Infrastructure;
using CID.Tests.Support;
using NUnit.Framework;

namespace CID.Domain.Persistence.Tests.Infrastructure
{
    [TestFixture]
    class DefinitionPersistenceTests : BasePersistenceWithDataTests
    {
        private static void AssertAreEqual(Definition expected, Definition actual)
        {
            Assert.AreEqual(expected.Id, actual.Id);
            CollectionAssert.AreEquivalent(expected.ParameterValues.Select(x => x.Id), actual.ParameterValues.Select(x => x.Id));
        }

        private static void AssertAreEqual(ActivationDeactivationDefinition expected, ActivationDeactivationDefinition actual)
        {
            AssertAreEqual(expected as Definition, actual as Definition);
            Assert.AreEqual(expected.Component.Id, actual.Component.Id);
            if (expected.ActivationTemplate == null) Assert.IsNull(expected.ActivationTemplate);
            else Assert.AreEqual(expected.ActivationTemplate.Id, actual.ActivationTemplate.Id);
            if (expected.DeactivationTemplate == null) Assert.IsNull(expected.DeactivationTemplate);
            else Assert.AreEqual(expected.DeactivationTemplate.Id, actual.DeactivationTemplate.Id);
        }

        private static void AssertAreEqual(DeploymentDefinition expected, DeploymentDefinition actual)
        {
            AssertAreEqual(expected as Definition, actual as Definition);
            Assert.AreEqual(expected.Version.Id, actual.Version.Id);
            if (expected.DeploymentTemplate == null) Assert.IsNull(expected.DeploymentTemplate);
            else Assert.AreEqual(expected.DeploymentTemplate.Id, actual.DeploymentTemplate.Id);
        }

        [Test]
        public void SaveNewActivationDeactivationDefinition_ActivationDeactivationDefinitionShouldBeSaved()
        {
            var session = OpenSession();
            var newComponent = Development.DataProvider.CreateComponent(session, OperationsData.ServerRole1, UsersData.User1);
            var newDefinition = (ActivationDeactivationDefinition)newComponent.ActivationDeactivationDefinition;
            session.SaveOrUpdate(newComponent);
            CleanSession(session);

            session = OpenSession();
            var retrievedDefinition = session.Get<Definition>(newDefinition.Id);
            AssertAreEqual(newDefinition, retrievedDefinition);
            CleanSession(session);
        }

        [Test]
        public void SaveModifiedActivationDeactivationDefinition_ChangesShouldBeSaved()
        {
            var session = OpenSession();
            var newComponent = Development.DataProvider.CreateComponent(session, OperationsData.ServerRole1, UsersData.User1);
            var newDefinition = (ActivationDeactivationDefinition)newComponent.ActivationDeactivationDefinition;
            session.SaveOrUpdate(newComponent);
            CleanSession(session);

            session = OpenSession();
            var modifiedComponent = Development.DataProvider.GetComponent(session, newComponent);
            var modifiedDefinition = (ActivationDeactivationDefinition)modifiedComponent.ActivationDeactivationDefinition;
            AssertAreEqual(newDefinition, modifiedDefinition); //Necessary to load lazy collections before the session is wiped out
            modifiedDefinition.ActivationTemplate = DataProvider.GetTemplate<ActivationTemplate>(session, InfrastructureData.ActivationTemplate);
            var activationParameter = DataProvider.GetParameter(session, InfrastructureData.ActivationTemplateBooleanParameter);
            modifiedDefinition.GetDefaultParameterValue(activationParameter).BooleanValue = true;
            modifiedDefinition.DeactivationTemplate = DataProvider.GetTemplate<DeactivationTemplate>(session, InfrastructureData.DeactivationTemplate);
            var deactivationParameter = DataProvider.GetParameter(session, InfrastructureData.DeactivationTemplateIntegerParameter);
            modifiedDefinition.GetDefaultParameterValue(deactivationParameter).IntegerValue = 123; 
            session.SaveOrUpdate(modifiedComponent);
            CleanSession(session);

            session = OpenSession();
            var retrievedDefinition = session.Get<Definition>(newDefinition.Id);
            AssertAreEqual(modifiedDefinition, retrievedDefinition);
            CleanSession(session);
        }

        [Test]
        public void DeleteActivationDeactivationDefinition_DefinitionShouldBeDeleted()
        {
            var session = OpenSession();
            var newDefinition1 = (ActivationDeactivationDefinition)Development.DataProvider.GetComponent(session, DevelopmentData.Component1).ActivationDeactivationDefinition;
            var newDefinition2 = (ActivationDeactivationDefinition)Development.DataProvider.GetComponent(session, DevelopmentData.Component2).ActivationDeactivationDefinition;
            session.SaveOrUpdate(newDefinition1);
            session.SaveOrUpdate(newDefinition2);
            CleanSession(session);

            session = OpenSession();
            var retrievedDefinition1 = session.Get<ActivationDeactivationDefinition>(newDefinition1.Id);
            session.Delete(retrievedDefinition1);
            CleanSession(session);

            session = OpenSession();
            retrievedDefinition1 = session.Get<ActivationDeactivationDefinition>(newDefinition1.Id);
            var retrievedDefinition2 = session.Get<ActivationDeactivationDefinition>(newDefinition2.Id);
            Assert.IsNull(retrievedDefinition1);
            Assert.IsNotNull(retrievedDefinition2);
            CleanSession(session);
        }

        [Test]
        public void SaveNewDeploymentDefinition_DeploymentDefinitionShouldBeSaved()
        {
            var session = OpenSession();
            var newVersion = Development.DataProvider.GetComponent(session, DevelopmentData.Component1).CreateVersion(GetRandomString(), GetRandomString());
            var newDefinition = (DeploymentDefinition)newVersion.DeploymentDefinition;
            session.SaveOrUpdate(newVersion);
            CleanSession(session);

            session = OpenSession();
            var retrievedDefinition = session.Get<Definition>(newDefinition.Id);
            AssertAreEqual(newDefinition, retrievedDefinition);
            CleanSession(session);
        }

        [Test]
        public void SaveModifiedDeploymentDefinition_ChangesShouldBeSaved()
        {
            var session = OpenSession();
            var newVersion = Development.DataProvider.GetComponent(session, DevelopmentData.Component1).CreateVersion(GetRandomString(), GetRandomString());
            var newDefinition = (DeploymentDefinition)newVersion.DeploymentDefinition;
            session.SaveOrUpdate(newVersion);
            CleanSession(session);

            session = OpenSession();
            var modifiedVersion = Development.DataProvider.GetVersion(session, newVersion);
            var modifiedDefinition = (DeploymentDefinition)modifiedVersion.DeploymentDefinition;
            AssertAreEqual(newDefinition, modifiedDefinition); //Necessary to load lazy collections before the session is wiped out
            modifiedDefinition.DeploymentTemplate = DataProvider.GetTemplate<DeploymentTemplate>(session, InfrastructureData.DeploymentTemplate);
            var deploymentParameter = DataProvider.GetParameter(session, InfrastructureData.DeploymentTemplateStringParameter);
            modifiedDefinition.GetDefaultParameterValue(deploymentParameter).StringValue = "Some string";
            session.SaveOrUpdate(modifiedVersion);
            CleanSession(session);

            session = OpenSession();
            var retrievedDefinition = session.Get<Definition>(newDefinition.Id);
            AssertAreEqual(modifiedDefinition, retrievedDefinition);
            CleanSession(session);
        }

        [Test]
        public void DeleteDeploymentDefinition_DefinitionShouldBeDeleted()
        {
            var session = OpenSession();
            var newVersion1 = Development.DataProvider.GetComponent(session, DevelopmentData.Component1).CreateVersion(GetRandomString(), GetRandomString());
            var newDefinition1 = (DeploymentDefinition)newVersion1.DeploymentDefinition;
            var newVersion2 = Development.DataProvider.GetComponent(session, DevelopmentData.Component2).CreateVersion(GetRandomString(), GetRandomString());
            var newDefinition2 = (DeploymentDefinition)newVersion2.DeploymentDefinition;
            session.SaveOrUpdate(newVersion1);
            session.SaveOrUpdate(newVersion2);
            CleanSession(session);

            session = OpenSession();
            var retrievedDefinition1 = session.Get<DeploymentDefinition>(newDefinition1.Id);
            var component = retrievedDefinition1.Version.Component;
            component.RemoveVersion(retrievedDefinition1.Version);
            session.SaveOrUpdate(component);
            CleanSession(session);

            session = OpenSession();
            retrievedDefinition1 = session.Get<DeploymentDefinition>(newDefinition1.Id);
            var retrievedDefinition2 = session.Get<DeploymentDefinition>(newDefinition2.Id);
            Assert.IsNull(retrievedDefinition1);
            Assert.IsNotNull(retrievedDefinition2);
            CleanSession(session);
        }
    }
}
